#ifndef __STDF_RECORDS_H__
#define __STDF_RECORDS_H__

#include <string>
#include <vector>
#include <ostream>
#include <map>

#include "types.h"

using namespace std;

namespace stdf {

string recordTypeToString( RecordType recType);
string recordTypeToString( U1 type, U1 subType);

typedef map<RecordType, pair<U1,U1> > RecordTypeCodeMap;
/// \brief STDF Record Header which is common to all STDF records
class RecordHeader {
    public:
        RecordHeader( U1 _type=0, U1 _subType=0, U2 _len=0);
        RecordHeader( RecordType recType);

        RecordHeader& operator=(RecordType& recType);

        RecordType getRecordType();
        string     getRecordTypeString();
        U2         getLength(void) { return length; }

        static void recordTypeToTypes( const RecordType& rec, U1& type, U1 & subType);

        friend class Stream;
        friend ostream& operator<<(ostream& os, RecordHeader& rh);

    protected:
        U2 length;
        U1 type;
        U1 subType;
        static RecordTypeCodeMap codeMap;
        static map<unsigned int, RecordType> codeToTypeMap;
};

/// \brief Abstract Base class for all STDF Records
class Record {
        public:
    Record(void);
    virtual ~Record() {}
    /// \brief Get length of Record in bytes
    virtual U2           getLength(void) = 0;
    /// Get key value sets of record fields
    virtual void         getFields(vector< pair<string,string> >& values) = 0;
    virtual RecordType getRecordType() = 0;

    virtual RecordHeader getRecordHeader(void) { return recordHeader; }

    friend ostream& operator<<(ostream& os, Record& rh);

        public:
    static string sep;

        protected:
    RecordHeader recordHeader;
};

class FARRecord : public Record {
        public:
            FARRecord(U1 cpu=0, U1 version=0);
            U2 getLength(void) { return 2; }
            void getFields( vector< pair<string,string> >& fields);
            RecordType getRecordType() { return FAR; }
            //void print(ostream& os, bool detailed=false);

            ByteOrder getByteOrder();
            unsigned char getCpuType() { return cpuType; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U1 cpuType;
            U1 stdfVersion;
    };

    class ATRRecord : public Record {
        public:
            ATRRecord();
            ATRRecord( U4 modTime, CN cmdLine);
            virtual ~ATRRecord() {}
            U2 getLength(void) { return (4 + commandLine.getLength()); }
            void getFields( vector< pair<string,string> >& fields);
            RecordType getRecordType() { return ATR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U4 modificationTime;
            CN commandLine;
    };

    class MIRRecord : public Record {
        public:
            MIRRecord();
            virtual ~MIRRecord() {}
            U2 getLength(void);
            void getFields(vector< pair<string,string> >& fields);
            RecordType getRecordType() { return MIR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U4 setupTime;
            U4 startTime;
            U1 stationNumber;
            C1 modeCode;
            C1 retestCode;
            C1 protectionCode;
            U2 burninTime;
            C1 commandModeCode;
            CN lotID;
            CN partType;
            CN nodeName;
            CN testerType;
            CN jobName;
            CN jobRevision;
            CN sublotID;
            CN operatorName;
            CN executiveType;
            CN executiveVersion;
            CN testCode;
            CN testTemp;
            CN userText;
            CN auxFile;
            CN packageType;
            CN familyID;
            CN dateCode;
            CN facilityID;
            CN floorID;
            CN processID;
            CN operatorFrequency;
            CN specName;
            CN specVersion;
            CN flowID;
            CN setupID;
            CN designRevision;
            CN engineeringLotID;
            CN romCode;
            CN serialNumber;
            CN supervisorName;
    };

#define MIR_ORDER(opr, obj)         opr obj.setupTime \
                                    opr obj.startTime \
                                    opr obj.stationNumber \
                                    opr obj.modeCode \
            opr obj.retestCode \
            opr obj.protectionCode \
            opr obj.burninTime \
            opr obj.commandModeCode \
            opr obj.lotID \
            opr obj.partType \
            opr obj.nodeName \
            opr obj.testerType \
            opr obj.jobName \
            opr obj.jobRevision \
            opr obj.sublotID \
            opr obj.operatorName \
            opr obj.executiveType \
            opr obj.executiveVersion \
            opr obj.testCode \
            opr obj.testTemp \
            opr obj.userText \
            opr obj.auxFile \
            opr obj.packageType \
            opr obj.familyID \
            opr obj.dateCode \
            opr obj.facilityID \
            opr obj.floorID \
            opr obj.processID \
            opr obj.operatorFrequency \
            opr obj.specName \
            opr obj.specVersion \
            opr obj.flowID \
            opr obj.setupID \
            opr obj.designRevision \
            opr obj.engineeringLotID \
            opr obj.romCode \
            opr obj.serialNumber \
            opr obj.supervisorName


    class MRRRecord : public Record {
        public:
            MRRRecord();
            virtual ~MRRRecord() {}
            U2 getLength(void);
            void getFields(vector< pair<string,string> >& fields);
            RecordType getRecordType() { return MRR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U4 finishTime;
            C1 dispositionCode;
            CN userLotDescription;
            CN executiveLotDescription;
    };

    class PCRRecord : public Record {
        public:
            PCRRecord();
            virtual ~PCRRecord() {}
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return PCR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U1 headNumber;
            U1 siteNumber;
            U4 partCount;
            U4 retestCount;
            U4 abortCount;
            U4 goodCount;
            U4 funcCount;
    };

    class HBRRecord : public Record {
        public:
            HBRRecord();
            virtual ~HBRRecord() {}
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return HBR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U1 headNumber;
            U1 siteNumber;
            U2 hbinNumber;
            U4 hbinCount;
            C1 hbinPF;
            CN hbinName;
    };

   class SDRRecord : public Record {
        public:
            SDRRecord();
            virtual ~ SDRRecord() {}
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return SDR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U1 headNumber;
            U1 siteGroup;
            U1 siteCount;
            vector<U1> siteNumbers;
            CN handlerType;
            CN handlerID;
            CN probeCardType;
            CN probeCardID;
            CN loadBoardType;
            CN loadBoardID;
            CN dibType;
            CN dibID;
            CN cableType;
            CN cableID;
            CN contactorType;
            CN contactorID;
            CN laserType;
            CN laserID;
            CN extraType;
            CN extraID;

   };

  class PMRRecord : public Record {
        public:
            PMRRecord();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return PMR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U2 pmrIndex;
            U2 channelType;
            CN channelName;
            CN physicalName;
            CN logicalName;
            U1 headNumber;
            U1 siteNumber;

   };

    class PGRRecord : public Record {
        public:
            PGRRecord();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return PGR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U2 groupIndex;
            CN groupName;
            U2 indexCount;
            std::vector<U2> pmrIndex;

   };

    class PIRRecord : public Record {
        public:
            PIRRecord();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return PIR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U1 headNumber;
            U1 siteNumber;

        };

    class PLRRecord : public Record {
        public:
            PLRRecord();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return PLR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U2 groupCount;
            vector<U2> groupIndex;
            vector<U2> groupMode;
            vector<U1> groupRadix;
            vector<CN> programCharRight;
            vector<CN> returnCharRight;
            vector<CN> programCharLeft;
            vector<CN> returnCharLeft;

        };

    class PTRRecord : public Record {
        public:
            PTRRecord();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return PTR; }

            friend class Stream;
            friend class StdfFile;

            //
            // testFlag decoding
            //
            bool isAlarm        (void) { return  ((testFlag & 0x01) > 0); }
            bool isResultValid  (void) { return !((testFlag & 0x02) > 0); }
            bool isTestReliable (void) { return !((testFlag & 0x04) > 0); }
            bool isTimeout      (void) { return  ((testFlag & 0x08) > 0); }
            bool isTestExecuted (void) { return  ((testFlag & 0x10) > 0); }
            bool isTestAborted  (void) { return  ((testFlag & 0x20) > 0); }
            bool isPFValid      (void) { return !((testFlag & 0x40) > 0); }
            bool isTestPass     (void) { return !((testFlag & 0x80) > 0); }
            //
            // parmFlag decoding
            //
            bool isScaleError   (void) { return  ((parmFlag & 0x01) > 0); }
            bool isDriftError   (void) { return  ((parmFlag & 0x02) > 0); }
            bool isOscillatior  (void) { return  ((parmFlag & 0x04) > 0); }
            bool isMeasHi       (void) { return  ((parmFlag & 0x08) > 0); }
            bool isMeasLo       (void) { return  ((parmFlag & 0x10) > 0); }
            bool isLoLimitPass  (void) { return  ((parmFlag & 0x40) > 0); }
            bool isHiLimitPass  (void) { return  ((parmFlag & 0x80) > 0); }

            bool considerResult (void) { return  !((bool) ((testFlag & 0x03F) | (parmFlag & 0x07))); }

        protected:
            U4 testNumber;
            U1 headNumber;
            U1 siteNumber;
            B1 testFlag;
            B1 parmFlag;
            R4 testResult;
            CN testText;
            CN alarmID;
            B1 optFlag;
            I1 resultScale;
            I1 llmScale;
            I1 hlmScale;
            R4 loLimit;
            R4 hiLimit;
            CN units;
            CN cResFmt;
            CN cLlmFmt;
            CN cHlmFmt;
            R4 loSpec;
            R4 hiSpec;

        };

    class PRRRecord : public Record {
        public:
            PRRRecord();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return PRR; }

            friend class Stream;
            friend class StdfFile;

            bool considerResult(void) { 
                if((hardBin == 65535) || (softBin == 65535)) 
                    return false; 
                else
                    return true;   
            }

        protected:
            U1 headNumber;
            U1 siteNumber;
            B1 partFlag;
            U2 numTests;
            U2 hardBin;
            U2 softBin;
            I2 xCoord;
            I2 yCoord;
            U4 testTime;
            CN partID;
            CN partText;
            BN partFix;

        };

    class TSRRecord : public Record {
        public:
            TSRRecord();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return TSR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U1 headNumber;
            U1 siteNumber;
            C1 testType;
            U4 testNumber;
            U4 execCount;
            U4 failCount;
            U4 alarmCount;
            CN testName;
            CN sequencerName;
            CN testLabel;
            B1 optFlag;
            R4 testTime;
            R4 testMin;
            R4 testMax;
            R4 testSums;
            R4 testSquares;

        };


    class WCRRecord : public Record {
        public:
            WCRRecord();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return WCR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            R4 waferSize;
            R4 dieHeight;
            R4 dieWidth;
            U1 waferUnits;
            C1 waferFlat;
            I2 centerX;
            I2 centerY;
            C1 positiveX;
            C1 positiveY;

        };


    class WIRRecord : public Record {
        public:
            WIRRecord();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return WIR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U1 headNumber;
            U1 siteGroup;
            U4 startTime;
            CN waferID;

        };


    class WRRRecord : public Record {
        public:
            WRRRecord();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return WRR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U1 headNumber;
            U1 siteGroup;
            U4 finishTime;
            U4 partCount;
            U4 retestCount;
            U4 abortCount;
            U4 goodCount;
            U4 funcCount;
            CN waferID;
            CN fabWaferID;
            CN waferFrameID;
            CN waferMaskID;
            CN userDescription;
            CN execDescription;

        };

    class SBRRecord : public Record {
        public:
            SBRRecord();
            U2 getLength(void);
            void getFields( vector< pair<string, string> >& fields);
            RecordType getRecordType() { return SBR; }

            friend class Stream;
            friend class StdfFile;

        protected:
            U1 headNumber;
            U1 siteNumber;
            U2 sbinNumber;
            U4 sbinCount;
            C1 sbinPF;
            CN sbinName;

        };

} // end namespace

#endif

